/**
 *  Copyright (C) 2008 Richard Hall
 *
 *  This program is free software; you can redistribute it and/or modify it under the terms of the 
 *  GNU General Public License as published by the Free Software Foundation; either version 3 of the 
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
 *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 *  See the GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along with this program; if not, 
 *  see <http://www.gnu.org/licenses>.
 *
 *  Additional permission under GNU GPL version 3 section 7
 *
 *  If you modify this Program, or any covered work, by linking or combining it with [name of library] 
 *  (or a modified version of that library), containing parts covered by the terms of 
 *  [name of library's license], the licensors of this Program grant you additional permission to 
 *  convey the resulting work. {Corresponding Source for a non-source form of such a combination shall 
 *  include the source code for the parts of [name of library] used as well as that of the 
 *  covered work.}
 *
 * 
 */

package com.gpsmedia.utils;


import com.gpsmedia.gui.frames.PictureFrame;
import com.gpsmedia.gui.frames.AudioFrame;
import com.gpsmedia.dataobject.NmeaData;
import com.gpsmedia.gui.frames.MainFrame;
import java.util.*;
import java.io.*;
import java.awt.*;
import javax.imageio.*;
import java.net.*;
import com.drew.metadata.*;
import com.drew.imaging.jpeg.*;
import java.text.SimpleDateFormat;
import com.gpsmedia.gui.*;

/**
 * This class is used for taking the data and finding links between gps
 * location, time and pictures and/or audio. The output from this class will be
 * the final data collection before it is written to the output file
 * 
 * @author Richard Hall
 */
public class FileCheck {

    private LinkedHashMap data;
    private File pictureFolder;
    private File audioFolder;
    private CalendarData calendarData;
    private PictureFrame pictureFrame;
    private AudioFrame audioFrame;

    /**
	 * Constructor for this class.
	 * 
	 * @param data
	 *            The data in form of a LinkedHashMap of NmeaData objects
	 * @param pictureFolder
	 *            The picture folder
	 * @param audioFolder
	 *            The audio folder
	 * @param picRealTime
	 *            the first picture time
	 * @param audioRealTime
	 *            The first audio time
	 * @param outputTimeZone
	 *            The time zone
	 */
    public FileCheck(LinkedHashMap data, String pictureFolder, String audioFolder,
            Calendar picRealTime, Calendar audioRealTime, TimeZone outputTimeZone) {
        this.data = data;
        if (pictureFolder.compareToIgnoreCase("") != 0) {
            this.pictureFolder = new File(pictureFolder);
        } else {
            this.pictureFolder = null;
        }

        if (audioFolder.compareToIgnoreCase("") != 0) {
            this.audioFolder = new File(audioFolder);
        } else {
            this.audioFolder = null;
        }

        calendarData = new CalendarData(picRealTime, audioRealTime, getFirstPicDate(),
                getFirstAudioDate(), outputTimeZone);
    }

    /**
	 * Returns the first picture according to time.
	 * 
	 * @return Calendar object of the first picture time
	 */
    private Calendar getFirstPicDate() {
        Calendar earliestTime = Calendar.getInstance();
        if (pictureFolder != null) {
            File[] currentFiles = pictureFolder.listFiles();
            if (currentFiles != null) {
                for (int i = 0; i < currentFiles.length; i++) {

                    File jpegFile = new File(currentFiles[i].getAbsolutePath());
                    if (jpegFile.getAbsolutePath().endsWith(".jpeg")||jpegFile.getAbsolutePath().endsWith(".jpg")||
                            jpegFile.getAbsolutePath().endsWith(".JPEG")||jpegFile.getAbsolutePath().endsWith(".JPG")) {
                        try {
                            Metadata metadata = JpegMetadataReader.readMetadata(jpegFile);

                            // iterate through metadata directories
                            Iterator directories = metadata.getDirectoryIterator();
                            while (directories.hasNext()) {
                                Directory directory = (Directory) directories.next();
                                // iterate through tags and print to System.out
                                Iterator tags = directory.getTagIterator();
                                while (tags.hasNext()) {
                                    Tag tag = (Tag) tags.next();
                                    // use Tag.toString()
                                    if (tag.getTagName().compareToIgnoreCase("Date/Time Original") == 0) {
                                        Calendar date = Calendar.getInstance();
                                        date.clear();
                                        date.set(Integer.valueOf(tag.getDescription().copyValueOf(tag.getDescription().toCharArray(), 0, 4)).intValue(), Integer.valueOf(tag.getDescription().copyValueOf(tag.getDescription().toCharArray(), 5, 2)).intValue() - 1, Integer.valueOf(tag.getDescription().copyValueOf(tag.getDescription().toCharArray(), 8, 2)).intValue(), Integer.valueOf(tag.getDescription().copyValueOf(tag.getDescription().toCharArray(), 11, 2)).intValue(), Integer.valueOf(tag.getDescription().copyValueOf(tag.getDescription().toCharArray(), 14, 2)).intValue(), Integer.valueOf(tag.getDescription().copyValueOf(tag.getDescription().toCharArray(), 17, 2)).intValue());
                                        //test adjust
                                        if (earliestTime.after(date) == true) {
                                            earliestTime = date;
                                        }
                                    }
                                }
                            }
                        } catch (Exception e) {

                        }
                    }
                }
            }
        }
        return earliestTime;
    }

    /**
	 * Returns the first audio according to time.
	 * 
	 * @return Calendar object of the first audio time
	 */
    private Calendar getFirstAudioDate() {
        Calendar earliestTime = Calendar.getInstance();
        if (audioFolder != null) {
            if (audioFolder.isDirectory()) {
                File[] currentFiles = audioFolder.listFiles();
                
                for (int i = 0; i < currentFiles.length; i++) {

                    File audioFile = new File(currentFiles[i].getAbsolutePath());
                    
                        try {
                            if (audioFile.getAbsolutePath().endsWith(".mp3")||audioFile.getAbsolutePath().endsWith(".MP3")) {

                                SimpleDateFormat formatter = new SimpleDateFormat("ddMMyyyyhhmmss");
                                Calendar date = Calendar.getInstance();
                                date.clear();
                                int[] dateData = getTimeFromString(audioFile.getName());
                                date.set(dateData[2], dateData[1] - 1, dateData[0], dateData[3], dateData[4], 0);

                                if (earliestTime.after(date) == true) {
                                    earliestTime = date;
                                }
                            }
                        } catch (Exception e) {

                        }
                    }
                
            }
        }
        return earliestTime;
    }

    /**
			 * Sets picture details and selects whether they are included or
			 * not. Uses the PictureFrame class. Can be used in the API, but the
			 * developer may want to consider writing their own.
     * @param showFrame Boolean sets whether to show frame or not 
     * @param frame Put in as a work around to a problem with user access to the main frame. Can be set to null
     * if being used as part of the API.
     */
    public void setPictureDetails(boolean showFrame, MainFrame frame) {
        pictureFrame = new PictureFrame(data, showFrame, frame);
        if (!showFrame) {
            pictureFrame.dispose();
        }

    }

    /**
     * Sets audio details and selects whether they are included or
     * not. Uses the AudioFrame class. Can be used in the API, but the
     * developer may want to consider writing their own.
     * @param showFrame Boolean sets whether to show frame or not
     * @param frame Put in as a work around to a problem with user access to the main frame. Can be set to null
     * if being used as part of the API.
		 */
    public void setAudioDetails(boolean showFrame, MainFrame frame) {
        audioFrame = new AudioFrame(data, showFrame, frame);
        if (!showFrame) {
            audioFrame.dispose();
        }


    }

    /**
	 * Returns an integer array of units of time taken from a string of known
	 * format. The format is the Apple ITunes automatic naming format. This may
	 * change.....
	 * 
	 * @param timeString The name of the audio file named by Apple ITunes
	 * @return The time array
	 */
    public int[] getTimeFromString(String timeString) {
        int[] timeSection = new int[5];
        //day
        timeSection[0] = Integer.parseInt(timeString.substring(0, 2));
        //month
        timeSection[1] = Integer.parseInt(timeString.substring(3, 5));
        //year
        timeSection[2] = Integer.parseInt(timeString.substring(6, 10));
        //hours
        timeSection[3] = Integer.parseInt(timeString.substring(11, 13));
        //minutes
        timeSection[4] = Integer.parseInt(timeString.substring(14, 16));
        return timeSection;
    }

    /**
	 * Links the audio file to the correct NmeaData object
	 * 
	 * @throws Exception
	 */
    public void tagAudio() throws Exception {

        if (audioFolder.isDirectory()) {
            File[] currentFiles = audioFolder.listFiles();

            for (int i = 0; i < currentFiles.length; i++) {

                File audioFile = new File(currentFiles[i].getAbsolutePath());
                
                    if (audioFile.getAbsolutePath().endsWith(".mp3")||audioFile.getAbsolutePath().endsWith(".MP3")) {
                        Calendar date = Calendar.getInstance();
                        date.clear();
                        int[] dateData = getTimeFromString(audioFile.getName());
                        date.set(dateData[2], dateData[1] - 1, dateData[0], dateData[3], dateData[4], 0);
                        date = calendarData.getCorrectAudioDate(date);
                        if (data.get(date) != null) {
                            NmeaData nd = (NmeaData) data.get(date);
                            nd.getAudio().setPath(audioFile.getAbsolutePath());
                            data.put(date, nd);
                        }
                    }

                
            }
        }

    }

    /**
	 * Links the picture file to the correct NmeaData object
	 * 
	 * @throws Exception
	 */
    public void tagPicture() throws Exception {
        if (pictureFolder.isDirectory()) {
            File[] currentFiles = pictureFolder.listFiles();

            for (int i = 0; i < currentFiles.length; i++) {

                File jpegFile = new File(currentFiles[i].getAbsolutePath());

                if (jpegFile.getAbsolutePath().endsWith(".jpg")||jpegFile.getAbsolutePath().endsWith(".jpeg")||
                        jpegFile.getAbsolutePath().endsWith(".JPG")||jpegFile.getAbsolutePath().endsWith(".JPEG")) {
                    Metadata metadata = JpegMetadataReader.readMetadata(jpegFile);

                    // iterate through metadata directories
                    Iterator directories = metadata.getDirectoryIterator();
                    while (directories.hasNext()) {
                        Directory directory = (Directory) directories.next();
                        // iterate through tags and print to System.out
                        Iterator tags = directory.getTagIterator();
                        while (tags.hasNext()) {
                            Tag tag = (Tag) tags.next();
                            // use Tag.toString()
                            if (tag.getTagName().compareToIgnoreCase("Date/Time Original") == 0) {

                                Calendar date = Calendar.getInstance();
                                date.clear();
                                date.set(Integer.valueOf(tag.getDescription().copyValueOf(tag.getDescription().toCharArray(), 0, 4)).intValue(), Integer.valueOf(tag.getDescription().copyValueOf(tag.getDescription().toCharArray(), 5, 2)).intValue() - 1, Integer.valueOf(tag.getDescription().copyValueOf(tag.getDescription().toCharArray(), 8, 2)).intValue(), Integer.valueOf(tag.getDescription().copyValueOf(tag.getDescription().toCharArray(), 11, 2)).intValue(), Integer.valueOf(tag.getDescription().copyValueOf(tag.getDescription().toCharArray(), 14, 2)).intValue(), Integer.valueOf(tag.getDescription().copyValueOf(tag.getDescription().toCharArray(), 17, 2)).intValue());
                                date = calendarData.getCorrectPictureDate(date);

                                if (data.get(date) != null) {
                                    NmeaData nd = (NmeaData) data.get(date);
                                    for (int j = 0; j < 10; j++) {
                                        if (nd.getPictures()[j].isInclude() == false) {
                                            nd.getPictures()[j].setPath(jpegFile.getAbsolutePath());
                                            j = 10;
                                        }
                                    }
                                    data.put(date, nd);
                                }



                            }
                        }
                    }
                }



            }
        }



    }

    /** Corrects all of the Calendar object dates for the entire data set. */
    public void correctTimeValue() {
        LinkedHashMap newMap = new LinkedHashMap();

        Collection col = data.values();
        Iterator it = col.iterator();
        while (it.hasNext()) {
            NmeaData nd = (NmeaData) it.next();

            nd.setDate(calendarData.getActualTimeZoneDate(nd.getDate()));
            newMap.put(nd.getDate(), nd);
        }

        data = newMap;
    }

    /**
	 * Returns the edited LinkedHashMap containing the NmeaData objects
	 * 
	 * @return The LinkedHashMap
	 */
    public LinkedHashMap getMap() {
        return data;
    }
}




